<?php

namespace app\admin\controller;

use Throwable;
use ba\Random;
use think\facade\Db;
use app\common\controller\Backend;
use app\common\model\RedemptionCode;

/**
 * 兑换码批次管理
 */
class RedemptionCodeBatch extends Backend
{
    /**
     * RedemptionCodeBatch模型对象
     * @var object
     * @phpstan-var \app\common\model\RedemptionCodeBatch
     */
    protected object $model;

    protected array|string $preExcludeFields = ['id',  'used_count',  'discount_amount', 'discount_percent', 'create_time', 'update_time'];

    protected string|array $quickSearchField = ['id', 'title'];

    public function initialize(): void
    {
        parent::initialize();
        $this->model = new \app\common\model\RedemptionCodeBatch();
    }

    /**
     * 查看
     * @throws Throwable
     */
    public function index(): void
    {
        // 如果是 select 则转发到 select 方法，若未重写该方法，其实还是继续执行 index
        if ($this->request->param('select')) {
            $this->select();
        }

        list($where, $alias, $limit, $order) = $this->queryBuilder();

        // 添加时间区间查询支持
        $startTime = $this->request->param('start_time', '');
        $endTime = $this->request->param('end_time', '');

        if ($startTime) {
            $startTimeStamp = is_numeric($startTime) ? $startTime : strtotime($startTime);
            $where[] = ['start_time', '>=', $startTimeStamp];
        }

        if ($endTime) {
            $endTimeStamp = is_numeric($endTime) ? $endTime : strtotime($endTime);
            $where[] = ['end_time', '<=', $endTimeStamp];
        }

        $res = $this->model
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);

        // 计算使用率
        // $res->each(function($item) {
        //     $item->usage_rate = $item->total_count > 0 ? round($item->used_count / $item->total_count * 100, 2) : 0;
        // });

        $this->success('', [
            'list'   => $res->items(),
            'total'  => $res->total(),
            'remark' => get_route_remark(),
        ]);
    }

    /**
     * 添加批次并自动生成兑换码
     * @throws Throwable
     */
    public function add(): void
    {
        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }

            $data = $this->excludeFields($data);
            if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
                $data[$this->dataLimitField] = $this->auth->id;
            }

            // 验证必要字段
            if (!isset($data['title']) || !isset($data['total_count']) || $data['total_count'] <= 0) {
                $this->error(__('批次标题和数量不能为空，数量必须大于0'));
            }

            // 转换时间格式为时间戳
            if (isset($data['start_time']) && $data['start_time']) {
                $data['start_time'] = strtotime($data['start_time']);
            }
            if (isset($data['end_time']) && $data['end_time']) {
                $data['end_time'] = strtotime($data['end_time']);
            }

            $result = false;
            Db::startTrans();
            try {
                // 创建批次
                $data['total_count'] = $data['total_count'];
                $data['used_count'] = 0;
                $data['create_time'] = time();
                $data['update_time'] = time();

                $result = $this->model->save($data);
                $batchId = $this->model->id;

                // 自动生成兑换码
                $this->generateRedemptionCodes($batchId, $data);

                Db::commit();
            } catch (Throwable $e) {
                Db::rollback();
                $this->error($e->getMessage());
            }
            if ($result !== false) {
                $this->success(__('批次创建成功，已自动生成兑换码'));
            } else {
                $this->error(__('No rows were added'));
            }
        }

        $this->success('', [
            'remark' => get_route_remark(),
        ]);
    }

    /**
     * 编辑
     * @throws Throwable
     */
    public function edit(): void
    {
        $pk  = $this->model->getPk();
        $id  = $this->request->param($pk);
        $row = $this->model->find($id);
        if (!$row) {
            $this->error(__('Record not found'));
        }

        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error(__('Parameter %s can not be empty', ['']));
            }

            $data   = $this->excludeFields($data);

            // 转换时间格式为时间戳
            if (isset($data['start_time']) && $data['start_time']) {
                $data['start_time'] = strtotime($data['start_time']);
            }
            if (isset($data['end_time']) && $data['end_time']) {
                $data['end_time'] = strtotime($data['end_time']);
            }

            $result = false;
            Db::startTrans();
            try {
                // 不允许修改已生成兑换码的批次的核心信息
                if ($row->total_count > 0) {
                    unset($data['total_count'], $data['discount_amount'], $data['code_prefix']);
                }

                $data['update_time'] = time();
                $result = $row->save($data);
                Db::commit();
            } catch (Throwable $e) {
                Db::rollback();
                $this->error($e->getMessage());
            }
            if ($result !== false) {
                $this->success(__('Update successful'));
            } else {
                $this->error(__('No rows updated'));
            }
        }

        // 转换时间戳为时间格式供前端显示
        if ($row->start_time) {
            $row->start_time = date('Y-m-d H:i:s', $row->start_time);
        }
        if ($row->end_time) {
            $row->end_time = date('Y-m-d H:i:s', $row->end_time);
        }

        $this->success('', [
            'row'    => $row,
            'remark' => get_route_remark(),
        ]);
    }

    /**
     * 删除
     * @param array $ids
     * @throws Throwable
     */
    public function del(): void
    {
        $dataLimitAdminIds = $this->getDataLimitAdminIds();
        if ($dataLimitAdminIds) {
            $this->model = $this->model->where($this->dataLimitField, 'in', $dataLimitAdminIds);
        }
        $ids     = $this->request->param('ids/a', []);
        if (!$ids) {
            $this->error(__('Parameter error'));
        }
        $where[] = [$this->model->getPk(), 'in', $ids];
        $data    = $this->model->where($where)->select();


        $count = 0;
        Db::startTrans();
        try {
            foreach ($data as $v) {
                // 不允许删除已有使用记录的批次
                if ($v->used_count > 0) {
                    continue;
                }

                // 删除该批次下的所有兑换码
                Db::name('redemption_code')->where('batch_id', $v->id)->delete();

                $count += $v->delete();
            }
            Db::commit();
        } catch (Throwable $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
        if ($count) {
            $this->success(__('Deleted successfully'));
        } else {
            $this->error(__('No rows were deleted There are already records of usage'));
        }
    }

    /**
     * 查看批次详情（包含兑换码列表）
     * @param int|string|null $id
     * @throws Throwable
     */
    public function detail(int|string $id): void
    {
        $row = $this->model->find($id);
        if (!$row) {
            $this->error(__('Record not found'));
        }

        // 获取该批次的兑换码列表
        $codes = \app\common\model\RedemptionCode::where('batch_id', $id)
            ->order('id desc')
            ->paginate(20);

        $this->success('', [
            'batch' => $row,
            'codes' => $codes->items(),
            'total' => $codes->total(),
            'remark' => get_route_remark(),
        ]);
    }

    /**
     * 生成兑换码
     * @param int $batchId 批次ID
     * @param array $batchData 批次数据
     * @throws Throwable
     */
    private function generateRedemptionCodes(int $batchId, array $batchData): void
    {
        $quantity = $batchData['total_count'];
        $prefix = $batchData['code_prefix'] ?? 'JYB'; // 默认前缀为JYB
        $codeLength = $batchData['code_length'] ?? 10;

        $codes = [];
        $existingCodes = [];

        for ($i = 0; $i < $quantity; $i++) {
            do {
                $code = RedemptionCode::generateUniqueCode($prefix, $codeLength);
                // 检查是否重复
                $exists = in_array($code, $existingCodes) ||
                    Db::name('redemption_code')->where('code', $code)->find();
            } while ($exists);

            $existingCodes[] = $code;

            // 根据max_uses_per_code判断使用类型
            $maxUses = $batchData['max_uses_per_code'] ?? 1;
            $type = $maxUses > 1 ? 'multiple' : 'single';

            $codes[] = [
                'code' => $code,
                'batch_id' => $batchId,
                'title' => $batchData['title'],
                'description' => $batchData['description'] ?? '',
                'type' => $type,
                'max_uses' => $maxUses,
                'used_count' => 0,
                'discount_amount' => $batchData['discount_amount'] ?? 0,
                'discount_percent' => $batchData['discount_percent'] ?? 0,
                'start_time' => $batchData['start_time'] ?? null,
                'end_time' => $batchData['end_time'] ?? null,
                'status' => '1',
                'admin_id' => $this->auth?->id ?: 0,
                'remark' => $batchData['remark'] ?? '',
                'create_time' => time(),
                'update_time' => time(),
            ];
        }

        // 批量插入兑换码
        if (!empty($codes)) {
            Db::name('redemption_code')->insertAll($codes);
        }
    }

    /**
     * 重新生成批次兑换码
     * @throws Throwable
     */
    public function regenerate(): void
    {
        $id = $this->request->param('id');
        if (!$id) {
            $this->error(__('Parameter error'));
        }

        $batch = $this->model->find($id);
        if (!$batch) {
            $this->error(__('Record not found'));
        }

        // 检查是否有已使用的兑换码
        $usedCount = Db::name('redemption_code')
            ->where('batch_id', $id)
            ->where('used_count', '>', 0)
            ->count();

        if ($usedCount > 0) {
            $this->error(__('该批次已有兑换码被使用，无法重新生成'));
        }

        Db::startTrans();
        try {
            // 删除该批次的所有兑换码
            Db::name('redemption_code')->where('batch_id', $id)->delete();

            // 重新生成兑换码
            $this->generateRedemptionCodes($id, $batch->toArray());

            Db::commit();
            $this->success(__('重新生成成功'));
        } catch (Throwable $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
    }
}
